/**
 * 
 * ### 本模块提供单资源CURD操作RPC服务
 * 
 * 接受参数定义参考 @packages/shared/ 包内 validator/api.valid.ts 文件
 * 
 * 其中 singleResourceSchema 定义外层JSON格式
 * 
 * options 参数为主要查询、提供数据等，参考 singleResourceOptionsSchema 定义JSON格式
 *  
 */

import { CONST_SingleResourceAction, createErrorMessage, ErrorMessage, singleResourceSchema, type IReqSingleResource, type ISingleResourceOptions, type SingleResourceActionType } from "@packages/shared"
import { getResourceByName, type ResourceConfig } from "../models"
import assert from 'assert'
import { registerRpcMethod, type RpcMethod } from "./core"
import { infoLog } from "../utils/log";

type TOptions = {
    queries: Record<string, string | number | [] | object>;
    filters: Record<string, string | number | object>;
};

/** 操作字符转义为mongodb关键字 */
const operatorConvert = (char: string) => {
    const operators: Record<string, string> = {
        ">": "$gt",
        gt: "$gt",
        ">=": "$gte",
        gte: "$gte",
        "<": "$lt",
        lt: "$lt",
        "<=": "$lte",
        lte: "$lte",
        "<>": "$ne",
        or: "$or",
        and: "$and",
        in: "$in",
        regex: "$regex",
        options: "$options",
    };
    return operators[char] || char;
};

/** 将对象中的运算符转换为mongodb关键字 */
const convertParamsToOptions = (obj: any): Record<string, any> => {
    const newObj: Record<string, any> = {};
    for (const key in obj) {
        if (Array.isArray(obj[key])) {
            if (typeof obj[key][0] !== "object")
                newObj[operatorConvert(key)] = obj[key];
            else newObj[operatorConvert(key)] = obj[key].map(convertParamsToOptions);
        } else if (typeof obj[key] === "object") {
            newObj[operatorConvert(key)] = convertParamsToOptions(obj[key]);
        } else {
            newObj[operatorConvert(key)] = obj[key];
        }
    }
    return newObj;
};


/** 构建列表查询参数 */
const buildOptions = (params: ISingleResourceOptions): TOptions => {
    const queries: Record<string, string | string[] | object> = params.query
        ? convertParamsToOptions(params.query)
        : {};
    const filters: Record<string, string | number | string[] | object> = {};

    if (params.fill) {
        filters.populate = params.fill;
    }
    if (params.sort) {
        filters.sort = params.sort;
    }
    if (params.field) {
        filters.select = params.field;
    }
    if (params.paging) {
        const page = Math.max(params.paging.page ?? 1, 1);
        const pagesize = Math.max(params.paging.pagesize ?? 10, 1);
        filters.skip = (page - 1) * pagesize;
        filters.limit = pagesize;
    }

    return { queries, filters };
};

/**
 * 将字符串转换为首字母大写的形式
 * @param str 需要转换的字符串
 * @returns 首字母大写的字符串
 */
const capitalize = (str: string): string => {
    return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
};


const _create = async (data: object, r: ResourceConfig) => {
    assert(data, createErrorMessage(ErrorMessage.Required, 'data参数'))
    const pd = r.validator.createValid.parse(data)
    return await r.model.insertOne(pd)
}

const _update = async (data: object, r: ResourceConfig) => {
    assert(data, createErrorMessage(ErrorMessage.Required, 'data参数'))
    const pd = r.validator.updateValid.parse(data)
    return await r.model.findByIdAndUpdate(pd._id, data, { new: true })
}

const _delete = async (data: object, r: ResourceConfig) => {
    assert(data, createErrorMessage(ErrorMessage.Required, 'data参数'))
    const pd = r.validator.deleteValid.parse(data)
    return await r.model.deleteOne({ _id: pd._id })
}

const _list = async (options: ISingleResourceOptions, r: ResourceConfig) => {
    const { queries, filters } = buildOptions(options)
    return await r.model.find(queries).setOptions(filters).lean();
}

const _one = async (options: ISingleResourceOptions, r: ResourceConfig) => {
    const { queries, filters } = buildOptions(options)
    return await r.model.findOne(queries).setOptions(filters).lean();
}

/**
 * 单资源操作函数，根据传入的参数对指定资源执行增删改查等操作
 * @param param - 请求参数对象，包含资源名称、操作类型和选项配置
 * @returns 返回对应操作的执行结果
 */
const singleResource = async (param: IReqSingleResource) => {

    infoLog('singleResrouce:')
    infoLog(param)

    //@ts-ignore
    const { resource = "", action = CONST_SingleResourceAction.LIST, options = {} } = param

    // 获取资源信息
    const r = getResourceByName(capitalize(resource))
    assert(r, createErrorMessage(ErrorMessage.NotFound, resource))

    // 权限检查
    assert(r.action.includes(action as SingleResourceActionType), createErrorMessage(ErrorMessage.NotAuth, action))

    // 根据不同操作类型执行对应逻辑
    if (action === CONST_SingleResourceAction.CREATE) { // 新增
        return await _create(options.data!, r)
    } else if (action === CONST_SingleResourceAction.UPDATE) { // 修改
        return await _update(options.data!, r)
    } else if (action === CONST_SingleResourceAction.DELETE) { // 删除
        return await _delete(options.data!, r)
    } else if (action === CONST_SingleResourceAction.LIST) { // 查询列表

        return await _list(options, r)
    } else if (action === CONST_SingleResourceAction.ONE) { // 获取单个
        return await _one(options, r)
    }
}

registerRpcMethod([{
    handler: singleResource as RpcMethod,
    auth: true,
    validator: singleResourceSchema,
    paramType: 'IReqSingleResource',
    returnType: 'Promise<any>'
}])